package com.netease.nie.service;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.lang.math.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.netease.nie.base.cache.redis.Redis;
import com.netease.nie.base.exceptions.BusinessException;
import com.netease.nie.base.protocol.SystemResponseCode;
import com.netease.nie.base.utils.ConvertUtils;
import com.netease.nie.base.utils.CopyUtils;
import com.netease.nie.config.AdminAreaProperties;
import com.netease.nie.constants.AddressDefaultCodeConstants;
import com.netease.nie.constants.CachePrefixConstants;
import com.netease.nie.dao.AddressDao;
import com.netease.nie.dto.AddressDto;
import com.netease.nie.dto.AdminProvinceDto;
import com.netease.nie.dto.AdminProvinceDto.CityProvinceDto;
import com.netease.nie.dto.ChooseAddrDto;
import com.netease.nie.model.Address;

@Service
public class AddressServiceImpl implements AddressService {

	@Autowired
	private AdminAreaProperties adminAreaProperties;
	
	@Autowired
	private AddressDao addressDao;
	
	@Autowired
	private Redis redis;

	private static final String DEFAULT_ADDRESS_PREFIX = CachePrefixConstants.UserPrefix.DEFAULT_ADDRESS_PREFIX;
	//正则表达式：验证手机号
    public static final String REGEX_MOBILE = "^1\\d{10}$";
	
	public List<AddressDto> listAddressByUserId(long userId) {
		List<Address> addressList = addressDao.listAddressByUserId(userId);

		int size = addressList.size();
		List<AddressDto> addressDtoList = new ArrayList<>(size);
		Address address = null;
		AddressDto addressDto = null;
		for (int i = 0; i < size; ++i) {
			address = addressList.get(i);
			addressDto = new AddressDto();
			CopyUtils.copy(addressDto, address);
			addressDto.setChooseAddrCode(address.getChooseAddr());
			replaceChooseAddress(addressDto);
			
			addressDtoList.add(addressDto);
		}

		return addressDtoList;
	}

	public AddressDto listAddressById(long id, long userId) {
		Address address = addressDao.listAddressById(id, userId);
		if (address == null)
			return null;

		AddressDto addressDto = new AddressDto();
		CopyUtils.copy(addressDto, address);
		
		return addressDto;
	}
	
	public AddressDto queryAddressById(long id, long userId) {
		AddressDto addressDto = listAddressById(id, userId);
		if (addressDto == null)
			return null;
		
		addressDto.setChooseAddrCode(addressDto.getChooseAddr());

		replaceChooseAddress(addressDto);			
		return addressDto;
	}

	public int saveAddress(AddressDto addressDto, long userId) {		
		String defaultAddressKey = DEFAULT_ADDRESS_PREFIX + userId;
		Integer result = 0;
		
		validDto(addressDto);

		Address defaultAddress = addressDao.listDefaultAddressByUserId(userId);

		Address address = new Address();
		CopyUtils.copy(address, addressDto);
		
		Long id = addressDto.getId();
		if (id == null || id <= 0) { // 插入新地址
			if (defaultAddress == null) // 用户没有默认地址，即地址列表为空，则设置第一条地址为默认地址
				address.setDefaultStatus(AddressDefaultCodeConstants.DEFAULT
						.getCode());
			else {
				if (address.getDefaultStatus() == AddressDefaultCodeConstants.DEFAULT.getCode()) {	//默认地址有变动
					defaultAddress.setDefaultStatus(AddressDefaultCodeConstants.NOT_DEFAULT.getCode());    //将原来的默认地址标记为非默认
					addressDao.updateAddress(defaultAddress);
					renameDefaultAddressInRedis(address, defaultAddressKey);		//缓存变动
				}
			}
			result = addressDao.addAddress(address);
		} else { 					// 修改地址
			if (address.getDefaultStatus() == AddressDefaultCodeConstants.DEFAULT.getCode()) {
				if (defaultAddress == null) {
					renameDefaultAddressInRedis(address, defaultAddressKey);                //缓存变动
				}else if (address.getId() != defaultAddress.getId()) {            //默认地址有变动
					defaultAddress.setDefaultStatus(AddressDefaultCodeConstants.NOT_DEFAULT.getCode());    //将原来的默认地址标记为非默认
					addressDao.updateAddress(defaultAddress);
					renameDefaultAddressInRedis(address, defaultAddressKey);                //缓存变动
				}
			}
			result = addressDao.updateAddress(address);
		}
		
		return result;
	}

	/**
	 * 验证输入参数
	 * 
	 * @param addressDto
	 */
	private void validDto(AddressDto addressDto) {
		if (addressDto == null)
			throw new BusinessException(
					SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),
					"输入参数不合法");
		
		if(!Pattern.matches(REGEX_MOBILE, addressDto.getMobile()))
			throw new BusinessException(
					SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),
					"请输入有效的手机号！");
		
		String chooseAddr = addressDto.getChooseAddr();
		if(chooseAddr == null)
			throw new BusinessException(
					SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),
					"请选择你所在省市！");
		Map<Integer, String> adminAreaMap = adminAreaProperties.getAdminAreaMap();

		try {  //校验省市选择
			String[] addrs = chooseAddr.split("-");
			Integer provinceCode = Integer.parseInt(addrs[0]);
			if(!adminAreaMap.containsKey(provinceCode))
				throw new BusinessException(
						SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),
						"省市选择错误！");
			if (addrs.length > 1) {
				Integer cityCode = Integer.parseInt(addrs[1]);
				if(!adminAreaMap.containsKey(cityCode) || cityCode <= provinceCode || cityCode >= provinceCode + 10000)
					throw new BusinessException(
							SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),
							"省市选择错误！");
				
			}
		} catch (NumberFormatException e) {
			throw new BusinessException(
					SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),
					"省市选择错误！");
		}		
	}

	/**
	 * 更新已有的默认地址为非默认地址
	 * 
	 * @param addressDtoList
	 */
	private void updateDefaultAddress(List<AddressDto> addressDtoList) {
		if(addressDtoList.isEmpty())
			return;
		
		int size = addressDtoList.size();
		AddressDto addressDto = null;
		for(int i = 0; i < size; ++i) {
			addressDto = addressDtoList.get(i);
			if(addressDto.getDefaultStatus() == AddressDefaultCodeConstants.DEFAULT.getCode()) {
				Address address = new Address();
				CopyUtils.copy(address, addressDto);
				
				address.setDefaultStatus(AddressDefaultCodeConstants.NOT_DEFAULT.getCode());
				addressDao.updateAddress(address);
			}
		}
	}

	public AddressDto listDefaultAddressByUserId(long userId) {	
		String defaultAddressKey = DEFAULT_ADDRESS_PREFIX + userId;
		boolean exists = redis.exists(defaultAddressKey);
		Address address = null;
		if (!exists) {
			address = addressDao.listDefaultAddressByUserId(userId);
			if (address != null) {
				try {
					Map<String, String> map = (Map<String, String>) ConvertUtils
							.javaBean2StringValueMap(address);
					redis.hmset(defaultAddressKey, map);        //TODO    缓存问题待解决
					redis.expire(defaultAddressKey, 3600);
				} catch (IllegalAccessException | IllegalArgumentException
						| InvocationTargetException | IntrospectionException e) {
					// e.printStackTrace();
				}
			}
			else return null;
		} else {
			try {
				String[] fields = ConvertUtils
						.getJavaBeanProperties(Address.class);
				if (fields != null) {
					Map<String, String> map = new HashMap<String, String>();
					List<String> strList = redis.hmget(defaultAddressKey, fields);
					int fieldsLen = fields.length;
					String text = null;
					for (int i = 0; i < fieldsLen; i++) {
						text = strList.get(i);
						map.put(fields[i], text);
					}
					address = (Address) ConvertUtils.map2JavaBean(Address.class,
							map);
				}
			} catch (InstantiationException | IllegalAccessException
					| IntrospectionException | InvocationTargetException e) {
				// e.printStackTrace();
			}
		}
		
		AddressDto addressDto = new AddressDto();
		if (address != null)
			CopyUtils.copy(addressDto, address);
			
		return addressDto;
	}
	
	public int deleteAddressById(Long id, Long userId){
		int result;
		String defaultAddressKey = DEFAULT_ADDRESS_PREFIX + userId;
		Address address = addressDao.listAddressById(id, userId);
		if (address == null || address.getUserId() != (userId))
			throw new BusinessException(SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),"输入参数不合法");
		
		if(address.getDefaultStatus() == AddressDefaultCodeConstants.DEFAULT.getCode()){
			List<Address> addressList = addressDao.listAddressByUserId(userId);
			int addressListSize = addressList.size();
			if(addressListSize >= 2){
				Address secondAddress = addressList.get(1);   //拿最新的地址作为默认地址
				secondAddress.setDefaultStatus(AddressDefaultCodeConstants.DEFAULT.getCode());
				 addressDao.updateAddress(secondAddress);
				renameDefaultAddressInRedis(secondAddress, defaultAddressKey);                //缓存变动
			} else {
				renameDefaultAddressInRedis(null, defaultAddressKey);                //缓存变动
			}
		}
		
		result = addressDao.deleteAddressById(id, userId);

		return result;
	}
	
	/**
	 * 删除缓存，重命名key
	 * @param address
	 * @param key
	 */
	private void renameDefaultAddressInRedis(Address address, String defaultAddressKey) {
		if(address == null) {
			redis.del(defaultAddressKey);
			return;
		}
		else{
			String ramdomKey = defaultAddressKey + RandomUtils.nextInt(10000) + "temp";
			try {
				Map<String, String> map = (Map<String, String>) ConvertUtils
						.javaBean2StringValueMap(address);
				redis.hmset(ramdomKey, map);
				redis.expire(defaultAddressKey, 3600);
				redis.rename(ramdomKey, defaultAddressKey);
				
			} catch (IllegalAccessException | IllegalArgumentException
					| InvocationTargetException | IntrospectionException e) {
				// e.printStackTrace();
			}			
		}
	}

	public AdminProvinceDto queryAdminProvinceDtos(ChooseAddrDto chooseAddrDto) {
		AdminProvinceDto adminProvinceDto = new AdminProvinceDto();
		if (chooseAddrDto == null)
			throw new BusinessException(SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),"输入参数不合法");
		
		int level = chooseAddrDto.getLevel();
		
		if (level == 0){
			List<CityProvinceDto> adminProvinceDtoList = adminAreaProperties.generateAdminProvinceDtoList();
			adminProvinceDto.setAdminProvinceDtoList(adminProvinceDtoList);
			return adminProvinceDto;
		} else if (level == 1) {
			int code = chooseAddrDto.getCode();
			if (code < 110000 || code > 820000)
				throw new BusinessException(SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),"输入code不合法");
			List<CityProvinceDto> adminCityDtoList = adminAreaProperties.generateAdminCityDtoList(code);
			if (adminCityDtoList != null && !adminCityDtoList.isEmpty()) {
				adminProvinceDto.setAdminCityDtoList(adminCityDtoList);
			}
			return adminProvinceDto;
		}else throw new BusinessException(SystemResponseCode.PARAM_VALUE_ILLEGAL.getCode(),"输入level不合法");
	}
	
	public void replaceChooseAddress(AddressDto addressDto) {
		String chooseAddr = addressDto.getChooseAddr();
		String replaceAddr;
		Map<Integer, String> adminAreaMap = adminAreaProperties.getAdminAreaMap();
		if (chooseAddr != null) {
			String[] addrs = chooseAddr.split("-");
			Integer provinceCode = Integer.parseInt(addrs[0]);
			replaceAddr = adminAreaMap.get(provinceCode);
			
			if (addrs.length > 1) {
				Integer cityCode = Integer.parseInt(addrs[1]);				
				replaceAddr = replaceAddr + "-" + adminAreaMap.get(cityCode);
			}
			addressDto.setChooseAddr(replaceAddr);
		}
	}

	public AddressDto queryDefaultAddressByUserId(long userId) {
		AddressDto addressDto = listDefaultAddressByUserId(userId);
		if (addressDto != null)
			replaceChooseAddress(addressDto);
		return addressDto;
	}
	
}
